package com.ray.ba.starter.code.generator;


import cn.hutool.db.Entity;
import cn.hutool.setting.dialect.Props;
import com.ray.ba.starter.code.generator.entity.ColumnEntity;
import com.ray.ba.starter.code.generator.entity.GenConfig;
import com.ray.ba.starter.code.generator.entity.TableEntity;
import com.ray.ba.starter.code.generator.util.DbUtil;
import com.ray.ba.starter.code.generator.util.StringUtil;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * TemplateBuilder
 *
 * @author ray
 * @date 2020/5/2
 */
public class CodeGeneratorBuilder {
    private static final String DATA_TYPE_PROPERTIES = "data-type.properties";

    private DataSource dataSource;

    private GenConfig genConfig;

    private List<TemplateResourceEnum> templateResourceList = new ArrayList<>(TemplateResourceEnum.values().length);

    CodeGeneratorBuilder() {

    }

    public CodeGeneratorBuilder dataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        return this;
    }

    public CodeGeneratorBuilder genConfig(GenConfig genConfig) {
        this.genConfig = genConfig;
        return this;
    }

    public CodeGeneratorBuilder templateResourceList(List<TemplateResourceEnum> templateResourceList) {
        this.templateResourceList = templateResourceList;
        return this;
    }

    public CodeGeneratorBuilder templateResourceEnum(TemplateResourceEnum templateResourceEnum) {
        this.templateResourceList.add(templateResourceEnum);
        return this;
    }

    public CodeGenerator build() {
        TableEntity tableEntity = populateTableEntity(dataSource, genConfig.getTableName());

        CodeGenerator generator = new CodeGenerator();
        generator.setGenConfig(this.genConfig);
        generator.setTemplateResourceList(this.templateResourceList);
        generator.setTableEntity(tableEntity);

        return generator;
    }


    private TableEntity populateTableEntity(DataSource dataSource, String tableName) {
        try {
            Entity table = DbUtil.queryTableByTableNameEquals(dataSource, tableName);
            List<Entity> columns = DbUtil.queryColumnByTableName(dataSource, tableName);
            return populateTableEntity(table, columns);
        } catch (SQLException e) {
            throw new IllegalArgumentException(String.format("table not exist in db %s", dataSource));
        }
    }

    private TableEntity populateTableEntity(Entity table, List<Entity> columns) {
        String tableName = table.getStr("tableName");
        String tableComment = table.getStr("tableComment");
        String className = StringUtil.toUpperCamelCase(tableName);
        String lowerClassName = StringUtil.toLowerCamelCase(tableName);
        boolean hasBigDecimal = false;

        List<ColumnEntity> columnEntityList = new ArrayList<>();
        ColumnEntity pkColumn = null;
        for (Entity column : columns) {
            ColumnEntity columnEntity = new ColumnEntity();
            columnEntity.setColumnName(column.getStr("columnName"));
            columnEntity.setColumnDataType(column.getStr("dataType"));
            columnEntity.setComments(column.getStr("columnComment"));
            columnEntity.setExtra(column.getStr("extra"));

            String fieldName = StringUtil.toLowerCamelCase(columnEntity.getColumnName());
            columnEntity.setFieldName(fieldName);

            Props columnFiledDataTypeMappings = getColumnFiledDataTypeMappings();
            String fieldDataType = columnFiledDataTypeMappings.getStr(columnEntity.getColumnDataType(), "unknownType");
            columnEntity.setFieldDataType(fieldDataType);
            if ("BigDecimal".equals(fieldDataType)) {
                hasBigDecimal = true;
            }

            //是否主键
            if ("PRI".equalsIgnoreCase(column.getStr("columnKey"))) {
                pkColumn = columnEntity;
            }
            columnEntityList.add(columnEntity);
        }

        TableEntity tableEntity = new TableEntity();
        tableEntity.setTableName(tableName);
        tableEntity.setComments(tableComment);
        tableEntity.setClassName(className);
        tableEntity.setLowerClassName(lowerClassName);
        tableEntity.setPk(pkColumn);
        tableEntity.setColumns(columnEntityList);
        tableEntity.setHasBigDecimal(hasBigDecimal);
        return tableEntity;
    }

    private Props getColumnFiledDataTypeMappings() {
        Props props = new Props(DATA_TYPE_PROPERTIES);
        props.autoLoad(true);
        return props;
    }


}
